babl_fish_reference(), create_name() are racy
authorRoman Lebedev <lebedev.ri@gmail.com>
Fri, 19 Aug 2016 18:01:03 +0000 (21:01 +0300)
committerØyvind Kolås <pippin@gimp.org>
Sat, 20 Aug 2016 17:26:00 +0000 (19:26 +0200)
create_name_internal() uses global static buffer to create name.
While this is definitely fast, it can't work concurrently.

I used snprintf()+malloc()+snprintf(), so the amount of allocated
memory for the string is optimal.

Alternatively, a mutex would solve the problem, not sure which
solution is faster / better.

babl/babl-fish-reference.c

index 4133e403fb64e8eb721e147480e4c7f941878362..fe75a71a924bbd559f0f7935d004d694dd7da1f1 100644 (file)
@@ -30,18 +30,45 @@ assert_conversion_find (const void *source,
   return ret;
 }
 
+static char *
+create_name_internal (char *buf,
+                      size_t maxlen,
+                      const Babl *source,
+                      const Babl *destination,
+                      int   is_reference)
+{
+  return snprintf (buf, maxlen, "%s %p %p",
+                   is_reference ? "ref "
+                   : "",
+                   source, destination);
+}
+
 static char *
 create_name (const Babl *source,
              const Babl *destination,
              int   is_reference)
 {
-  static char buf[1024];
+  int size = 0;
+  char *buf = NULL;
+
+  size = create_name_internal (buf, size, source, destination, is_reference);
+
+  if (size < 0)
+    return NULL;
+
+  size++;             /* For '\0' */
+  buf = malloc (size);
+  if (buf == NULL)
+    return NULL;
+
+  size = create_name_internal (buf, size, source, destination, is_reference);
+
+  if (size < 0)
+    {
+      free (buf);
+      return NULL;
+    }
 
-  /* fish names are intentionally kept short */
-  snprintf (buf, 1024, "%s %p %p",
-            is_reference ? "ref "
-            : "",
-            source, destination);
   return buf;
 }
 
@@ -53,12 +80,15 @@ babl_fish_reference (const Babl *source,
   Babl *babl = NULL;
   char *name = create_name (source, destination, 1);
 
+  babl_assert (name);
+
   babl = babl_db_exist_by_name (babl_fish_db (), name);
   if (babl)
     {
       /* There is an instance already registered by the required name,
        * returning the preexistent one instead.
        */
+      free (name);
       return babl;
     }
 
@@ -87,6 +117,7 @@ babl_fish_reference (const Babl *source,
    * name, inserting newly created class into database.
    */
   babl_db_insert (babl_fish_db (), babl);
+  free (name);
   return babl;
 }